
package poker.util;

import poker.beliefs.Card;
import poker.beliefs.Hand;

/**
 *  Utility class with methods to find the rank of a hand
 */

public class HandChecker {

	// Values for the hand ranks
	public static final int HIGH_CARD 		= 0,
							ONE_PAIR		= 1,
							TWO_PAIRS		= 2,
							THREE_OF_A_KIND = 3,
							STRAIGHT		= 4,
							FLUSH			= 5,
							FULL_HOUSE		= 6,
							FOUR_OF_A_KIND	= 7,
							STRAIGHT_FLUSH	= 8,
							ROYAL_FLUSH		= 9;
	
	public static final int POKER_HAND_LENGTH = 5;
	
	
	public static int rankHand(Hand h) {
		if 		(checkRoyalFlush(h)) 	return ROYAL_FLUSH;
		else if (checkStraightFlush(h)) return STRAIGHT_FLUSH;
		else if (checkFourOfAKind(h)) 	return FOUR_OF_A_KIND;
		else if (checkFullHouse(h)) 	return FULL_HOUSE;
		else if (checkFlush(h)) 		return FLUSH;
		else if (checkStraight(h)) 		return STRAIGHT;
		else if (checkThreeOfAKind(h)) 	return THREE_OF_A_KIND;
		else if (checkTwoPairs(h)) 		return TWO_PAIRS;
		else if (checkOnePair(h)) 		return ONE_PAIR;
		else 							return HIGH_CARD;
	}
	
	public static boolean checkOnePair(Hand h) {
		int [] hits = new int[15];
		for (int i = 0; i < h.getCardCount(); i++) {
			if ((hits[h.getCard(i).getCValue()]++) == 1) return true;
		}
		return false;
	}
	
	public static boolean checkTwoPairs(Hand h) {
		int [] hits = new int[15];
		int pair = 0;
		for (int i = 0; i < h.getCardCount(); i++) {
			if ((hits[h.getCard(i).getCValue()]++) == 1) pair++;
			if (pair == 2) return true;
		}
		return false;
	}

	public static boolean checkThreeOfAKind(Hand h) {
		int [] hits = new int[15];
		for (int i = 0; i < h.getCardCount(); i++) {
			if ((hits[h.getCard(i).getCValue()]++) == 2) return true;
		}
		return false;
	}

	public static boolean checkStraight(Hand h) {
		//Simple Straight
		h.sortByValue();
		int numConsecutive = 1;
		int value = h.getCard(0).getCValue();
		for (int i = 1; i < h.getCardCount(); i++) {
			//Si els valors no son creixents d'un en un: out! -> cal trobar 5
			if (h.getCard(i).getCValue() == value++) {
				numConsecutive++;
				if (numConsecutive == POKER_HAND_LENGTH) return true;
			}
			else {
				numConsecutive = 1;
				value = h.getCard(i).getCValue();
			}
		}
		return false;
	}
	
	public static boolean checkFlush(Hand h) {
		//Check if the suit is always the same -> 5 cards with the same suit
		h.sortBySuit();
		int sameSuit = 1;
		int suit = h.getCard(0).getSuit();
		for (int i = 1; i < h.getCardCount(); i++){
			if (h.getCard(i).getSuit() == suit) {
				sameSuit++;
				if (sameSuit == POKER_HAND_LENGTH) return true;
			}
			else {
				sameSuit = 1;
				suit = h.getCard(i).getSuit();
			}
		}
		return false;
	}
	
	public static boolean checkFullHouse(Hand h) {
		int [] hits = new int[15];
		boolean trip = false, pair = false;
		
		for (int i = 0; i < h.getCardCount(); i++)
			hits[h.getCard(i).getCValue()]++;
		
		for (int i = 0; i < hits.length; i++) {
			if 		(hits[i] == 2) pair = true;
			else if (hits[i] == 3) trip = true;
		}
		
		return pair && trip;
	}

	public static boolean checkFourOfAKind(Hand h) {
		int [] hits = new int[15];
		for (int i = 0; i < h.getCardCount(); i++) {
			if ((hits[h.getCard(i).getCValue()]++) == 3) return true;
		}
		return false;
	}

	public static boolean checkStraightFlush(Hand h) {
		//Straight with one suit
		// Sorts by suit and by value inside a suit
		h.sortBySuit();
		
		int numFlush = 1;
		int suit = h.getCard(0).getSuit();
		int value = h.getCard(0).getCValue();
		for (int i = 1; i < h.getCardCount(); i++) {
			// Si els valors no son creixents d'un en un o pals diferents: out! -> cal trobar 5 consecutius
			if (h.getCard(i).getCValue() == value++ && h.getCard(i).getSuit() == suit) {
				numFlush++;
				if (numFlush == POKER_HAND_LENGTH) return true;
			}
			else {
				numFlush = 1;
				value = h.getCard(i).getCValue();
				suit = h.getCard(i).getSuit();
			}
		}
		return false;
	}

	public static boolean checkRoyalFlush(Hand h) {
		//10-J-Q-K-A and one suit
		//royal flush = straight flush + lastcard == ACE
		
		// Sorts by suit and by value inside a suit
		h.sortBySuit();
		
		int numFlush = 1;
		int suit = h.getCard(0).getSuit();
		int value = h.getCard(0).getCValue();
		for (int i = 1; i < h.getCardCount(); i++) {
			// Si els valors no son creixents d'un en un o pals diferents: out! -> cal trobar 5 consecutius
			if (h.getCard(i).getCValue() == value++ && h.getCard(i).getSuit() == suit) {
				numFlush++;
				if (numFlush == POKER_HAND_LENGTH
					&&
					h.getCard(i).getCValue() == Card.ACE)
					return true;
			}
			else {
				numFlush = 1;
				value = h.getCard(i).getCValue();
				suit = h.getCard(i).getSuit();
			}
		}
		return false;
	}
	
}
